
#include "telnet_opt.hpp"

void telnet_opt::init()
{
    _sb_len = 0;
    _width = _height = 0;
    _iac = _iac_sb_in_progress = 0;

    char sga_opt[] = { IAC, WILL, TELOPT_SGA, '\0' };
    char naws_opt[] = { IAC, DO, TELOPT_NAWS, '\0' };
    char echo_opt[] = { IAC, WILL, TELOPT_ECHO, '\0' };
    char line_opt[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };

    _opt_maps[SGA_OPT] = std::string(sga_opt);
    _opt_maps[NAWS_OPT] = std::string(naws_opt);
    _opt_maps[ECHO_OPT] = std::string(echo_opt);
    _opt_maps[LINE_OPT] = std::string(line_opt);
}

const std::string& 
telnet_opt::get_option_str(const OPT_TYPE type)
{
    return _opt_maps[type];
}

int 
telnet_opt::check_opt(unsigned char c)
{
    /* FIXME: 개선하삼... */

    if (c == IAC) {
        if (!_iac) {
            _iac = 1;
            return 1;
        } else {
            _iac = 0;
        }
    }

    if (_iac_sb_in_progress && !_iac) {
        if (_sb_len < sizeof(_sb_buf)) {
            _sb_buf[_sb_len] = c;
            _sb_len++;
        } 
        return 1;
    }

    return 0;
}

int 
telnet_opt::handle_opt(unsigned char c)
{
    switch (c) {
    case SB:
        _sb_len = 0;
        _iac_sb_in_progress = 1;
        return 0;
        break;
    case SE: 
    {
        if (!_iac_sb_in_progress) { 
            return 0;
        }

        if ((_sb_len == 0) || (_sb_buf[0] == '\0'))
        {
            _iac_sb_in_progress = 0;
            return 0;
        }
        switch (_sb_buf[0])
        {
            case TELOPT_NAWS:
                if (_sb_len != TELNET_NAWS_SB_LEN)
                    PDBG( "RFC 1073 violation detected: telnet NAWS option "
                            "should send %d characters, but we received %lu\n",
                            TELNET_NAWS_SB_LEN, (u_long)_sb_len);
                else if (sizeof(_sb_buf) < TELNET_NAWS_SB_LEN)
                    PDBG("Bug detected: sizeof(_sb_buf) %lu < %d, "
                            "too small to handle the telnet NAWS option\n",
                            (u_long)sizeof(_sb_buf), TELNET_NAWS_SB_LEN);
                else
                {
                    _width = ((_sb_buf[1] << 8)|_sb_buf[2]);
                    _height = ((_sb_buf[3] << 8)|_sb_buf[4]);
                    
                    //_vtyOut.changedTermSize(_width, _height);
                    PDBG("TELNET NAWS window size negotiation completed: "
                            "_width %d, _height %d\n",
                            _width, _height);
                }
                break;
            default:
                break;
        }
        _iac_sb_in_progress = 0;
        break;
    }
    default:
        break;
    }
    _iac = 0;
    return 1;
}

void 
telnet_opt::dump(unsigned char* buf, int len)
{

#define __TEL_DEBUG__
#ifdef __TEL_DEBUG__
#undef PDBG
#define PDBG(__fmt__, __args__ ...) printf(__fmt__, ## __args__)
    for (int idx=0; idx < len; idx++) {
        unsigned char c = buf[idx];
    switch (buf[idx])
    {
        case IAC:
            PDBG("IAC ");
            break;
        case WILL:
            PDBG("WILL ");
            break;
        case WONT:
            PDBG("WONT ");
            break;
        case DO:
            PDBG("DO ");
            break;
        case DONT:
            PDBG("DONT ");
            break;
        case SB:
            PDBG("SB ");
            break;
        case SE:
            PDBG("SE ");
            break;
        case TELOPT_ECHO:
            PDBG("TELOPT_ECHO\n");
            break;
        case TELOPT_SGA:
            PDBG("TELOPT_SGA\n");
            break;
        case TELOPT_NAWS:
            PDBG("TELOPT_NAWS\n");
            break;
        default:
            PDBG("%02X ", c);
            //_vtyOut.outputFmt("%X02 ", c);
            break;
    }
    }
    PDBG("\n");
#endif  /* __TEL_DEBUG__ */
}

